home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-04-04 | 29.6 KB | 987 lines | [TEXT/KAHL] |
- /***************************************************** IMPLEMENTATION
- DATE: 10/28/93
- AUTHOR: Eric R. Rosé
-
- CLASS: CPPVisualTreeNode
-
- SUPERCLASS: CPPTreeNode
-
- This C++ class manages the visual representation of a node
- in a hierarchical tree
-
- ********************************************************************/
-
- #include <CPPVisualTreeNode.h>
- #include <CPPVisualTree.h>
- #include "CPPString.h"
- #include <MathTools.h>
- #include <StringTools.h>
- #include <ConvertTools.h>
- #include <ToolboxTools.h>
- #include <math.h>
-
-
- #define hMargin 2
- #define vMargin 2
-
- /*-----------------------------------------------------------------*/
- /*------------------------ APPLY ROUTINES -------------------------*/
- /*-----------------------------------------------------------------*/
-
- void SetMustResize (CPPTreeNode *theNode, long param)
- /* set the value of 'needsResize' to the passed-in value */
- {
- if (theNode)
- {
- ((CPPVisualTreeNode *)theNode)->needsResize = (Boolean)param;
- ((CPPVisualTreeNode *)theNode)->needsMove = (Boolean)param;
- }
- }
-
- void SetMustMove (CPPTreeNode *theNode, long param)
- /* set the value of 'needsMove' to the passed-in value */
- {
- if (theNode)
- ((CPPVisualTreeNode *)theNode)->needsMove = (Boolean)param;
- }
-
- void SetNotYetPlaced (CPPTreeNode *theNode, long param)
- /* set the value of 'needsDraw' to the passed-in value */
- {
- if (theNode)
- ((CPPVisualTreeNode *)theNode)->notYetPlaced = (Boolean)param;
- }
-
- void SetMustDraw (CPPTreeNode *theNode, long param)
- /* set the value of 'needsDraw' to the passed-in value */
- {
- if (theNode)
- ((CPPVisualTreeNode *)theNode)->needsDraw = (Boolean)param;
- }
-
- void CountSelected (CPPTreeNode *theNode, long param)
- /* if the node is selected, increment param */
- {
- if (((CPPVisualTreeNode *)theNode)->IsSelected())
- (*((long *)param))++;
- }
-
- /*-----------------------------------------------------------------*/
- /*------------------------ PUBLIC METHODS -------------------------*/
- /*-----------------------------------------------------------------*/
-
- CPPVisualTreeNode::CPPVisualTreeNode (CPPObject *NodeData,
- CPPTree *BelongsTo,
- Boolean becomeOwner,
- Boolean selected) :
- CPPTreeNode (NodeData, BelongsTo, becomeOwner)
- {
- SetPt (&this->nodeSize, 0, 0);
- this->familySize = this->childSize = this->nodeSize;
-
- SetRect (&this->nodeRect, 0, 0, 0, 0);
- this->familyRect = this->childRect = this->nodeRect;
-
- this->needsDraw = TRUE;
- this->needsResize = TRUE;
- this->needsMove = TRUE;
- this->isSelected = selected;
- this->notYetPlaced = TRUE;
- }
-
- /*-----------------------------------------------------------------*/
-
- CPPVisualTreeNode::~CPPVisualTreeNode (void)
- {
-
- }
-
- /*-----------------------------------------------------------------*/
-
- Boolean CPPVisualTreeNode::Member (char *className)
- {
- if (strcmp(className, CPPVisualTreeNode::ClassName()) == 0)
- return TRUE;
- else
- return CPPTreeNode::Member(className);
- }
-
- /*-----------------------------------------------------------------*/
-
- char *CPPVisualTreeNode::ClassName (void)
- {
- return "CPPVisualTreeNode";
- }
-
- /*-----------------------------------------------------------------*/
-
- CPPObject *CPPVisualTreeNode::Clone(void)
- {
- return NULL;
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTreeNode::DrawNodeData (void)
- /* This method draws the specific data for the node */
- /* SUBCLASS SHOULD OVERRIDE */
- {
- StringPtr STemp;
- Rect tempRect = this->nodeRect;
-
- /*•*/
- if (this->nodeData)
- {
- STemp = ((CPPString *)this->nodeData)->GetString(TRUE);
- if (STemp)
- {
- PStrReplace (STemp, ' ', '\r');
- TextBox (STemp+1, *STemp, &tempRect, teJustCenter);
- DisposePtr((Ptr)STemp);
- }
- }
- /*•*/
-
- FrameRect (&tempRect);
- if (this->IsSelected())
- {
- InsetRect(&tempRect, 1, 1);
- InvertRect(&tempRect);
- }
- }
-
- /*-----------------------------------------------------------------*/
-
- Boolean CPPVisualTreeNode::CanDraw (void)
- /* Return TRUE either if this node needs to redraw, or the */
- /* tree's ForceDraw variable is set to TRUE */
- {
- if (this->needsDraw)
- return TRUE;
- else
- {
- if ((this->Root) && ((CPPVisualTree *)this->Root)->forceDraw)
- return TRUE;
- }
- return FALSE;
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTreeNode::DrawNode (Boolean wholeFamily,
- Boolean forceDraw)
- {
- CPPVisualTreeNode *theChild;
-
- if (!CanDraw() && !forceDraw && !wholeFamily) return;
-
- // prepare the grafport to draw tree nodes
- if (this->Root)
- ((CPPVisualTree *)this->Root)->Prepare(this);
-
- if (CanDraw() || forceDraw)
- {
- // draw the join between this node and its parent
- if (this->Parent)
- DrawJoin ((CPPVisualTreeNode *)this->Parent, this);
-
- // draw the data in the node;
- DrawNodeData();
-
- this->needsDraw = FALSE;
- }
-
- // draw the node's children
- if (wholeFamily)
- {
- for (long i = 1; i <= this->numItems; i++)
- {
- theChild = (CPPVisualTreeNode *)NthChild (i);
- if (theChild)
- theChild->DrawNode(wholeFamily, forceDraw);
- }
- }
-
- // restore the original grafport state
- ((CPPVisualTree *)this->Root)->Restore(this);
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTreeNode::EraseJoin (CPPVisualTreeNode *FromNode,
- CPPVisualTreeNode *ToNode)
- /* erase the join between the two passed-in nodes. This method */
- /* simply uses the Tree's default join method which takes into */
- /* account the orientation and join type of the tree */
- {
- PenState OldState;
-
- GetPenState (&OldState);
- PenMode (patBic);
- DrawJoin (FromNode, ToNode);
- SetPenState (&OldState);
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTreeNode::DrawJoin (CPPVisualTreeNode *FromNode,
- CPPVisualTreeNode *ToNode)
- /* Draw the join between the two passed-in nodes. This method */
- /* simply uses the Tree's default join method which takes into */
- /* account the orientation and join type of the tree */
- {
- if ((FromNode && !FromNode->notYetPlaced) &&
- (ToNode && !ToNode->notYetPlaced) &&
- this->Root)
- ((CPPVisualTree *)this->Root)->DrawDefaultJoin (FromNode, ToNode);
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTreeNode::EraseNode (Boolean wholeFamily)
- {
- PenState OldState;
-
- // prepare the grafport to draw tree nodes
- if (this->Root)
- ((CPPVisualTree *)this->Root)->Prepare(this);
-
- if (wholeFamily)
- {
- EraseRect (&this->familyRect);
- ApplyToFamily (this, SetMustDraw, (long)TRUE);
- }
- else
- EraseRect (&this->nodeRect);
-
- EraseJoin((CPPVisualTreeNode *)this->Parent, this);
-
- // restore the original grafport state
- ((CPPVisualTree *)this->Root)->Restore(this);
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTreeNode::CalcFamilyBounds (Point TopLeftCorner)
- /* Given the top left corner of the tree, call DoCalcFamilyBounds */
- /* with the apropriate parameter depending on the orientation of */
- /* the tree */
- {
- short deltaH = TopLeftCorner.h - this->familyRect.left,
- deltaV = TopLeftCorner.v - this->familyRect.top;
- Point TopRight = {this->familyRect.top + deltaV, this->familyRect.right + deltaH},
- BottomLeft = {this->familyRect.bottom + deltaV, this->familyRect.left + deltaH};
-
- if (!this->needsMove) return;
- this->needsMove = FALSE;
-
- // then figure out where everybody goes
- switch (GetOrientation()) {
- case kTopDown:
- case kLeft2Right :
- DoCalcFamilyBounds (TopLeftCorner);
- break;
- case kBottomUp:
- DoCalcFamilyBounds (BottomLeft);
- break;
- case kRight2Left:
- DoCalcFamilyBounds (TopRight);
- break;
- }
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTreeNode::CalcFamilySize (void)
- {
- DoCalcFamilySize();
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTreeNode::ResizeFamily (Boolean wholeFamily)
- /* set the 'must resize' flags of the node (and maybe its family) */
- /* then make the call to resize and calculate the new boundaries */
- /* of each node */
- {
- Point oldTopLeft = {this->familyRect.top, this->familyRect.left};
-
- if (wholeFamily)
- ApplyToFamily (this, SetMustResize, (long)TRUE);
- this->needsResize = TRUE;
- this->needsMove = TRUE;
-
- // first figure out how big everyone is
- CalcFamilySize();
-
- // then figure out where everybody goes
- CalcFamilyBounds(oldTopLeft);
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTreeNode::MoveFamily (Point *topLeft)
- /* move the family over to the specified coordinates */
- {
- Point oldTopLeft = {this->familyRect.top, this->familyRect.left};
-
- if (!EqualPt(*topLeft, oldTopLeft))
- {
- ApplyToFamily(this, SetMustMove, (long)TRUE);
- CalcFamilyBounds(*topLeft);
- }
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTreeNode::CalcNodeSize()
- /* Calculate how large our node's data is and store in nodeSize */
- /* SUBCLASS SHOULD OVERRIDE */
- {
- /*•*/
- FontInfo fInfo;
- StringPtr STemp = NULL;
- short maxWidth = 0;
- StringPtr STraverse = NULL;
- short lineCount = 1;
- short lastReturn=1, thisReturn= 1;
-
- if (this->Root)
- ((CPPVisualTree *)this->Root)->Prepare(this);
-
- GetFontInfo (&fInfo);
-
- if (this->nodeData)
- STemp = ((CPPString *)this->nodeData)->GetString(TRUE);
- if (STemp)
- {
- lineCount = PStrReplace(STemp, ' ', '\r') + 1;
- if (lineCount == 1)
- this->nodeSize.h = StringWidth(STemp) + hMargin * 2;
- else
- {
- // find the maximum length string
- while (thisReturn <= *STemp)
- {
- thisReturn = PStrPos(STemp, '\r', lastReturn);
- if (!thisReturn)
- thisReturn = *STemp + 1;
- if (STraverse)
- DisposePtr((Ptr)STraverse);
- STraverse = Data2PString(STemp+lastReturn, thisReturn - lastReturn);
- maxWidth = Max (maxWidth, StringWidth(STraverse));
- lastReturn = thisReturn + 1;
- }
- this->nodeSize.h = maxWidth + hMargin * 2;
- }
- DisposePtr((Ptr)STemp);
- }
- else
- this->nodeSize.h = 10;
-
- this->nodeSize.v = (fInfo.ascent + fInfo.descent + fInfo.leading) * lineCount + vMargin;
-
- if (this->Root)
- ((CPPVisualTree *)this->Root)->Restore(this);
-
- /*•*/
-
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTreeNode::DoCalcFamilySize(void)
- /* Calculate how large the node's children, and the entire node */
- /* are, storing the values in childSize and familySize */
- {
- CPPVisualTreeNode *theChild;
- orientStyle Orient = GetOrientation();
-
- if (!this->needsResize) return;
- this->needsResize = FALSE;
- this->CalcNodeSize(); // figure out node's size first
-
-
- SetPt (&this->childSize, 0, 0); // assume we have no children
-
- // iterate over all the children of this node, accumulating
- // their height and width
- for (long i = 1; i<= this->numItems; i++)
- {
- theChild = (CPPVisualTreeNode *)NthChild(i);
- theChild->CalcFamilySize();
- if ((Orient == kTopDown) || (Orient == kBottomUp))
- {
- childSize.h += theChild->familySize.h;
- childSize.v = Max (theChild->familySize.v, childSize.v);
- }
- else
- {
- childSize.v += theChild->familySize.v;
- childSize.h = Max (theChild->familySize.h, childSize.h);
- }
- }
-
- // Set the size of the node - a combination of the node size,
- // child size, and branch length;
- if ((Orient == kTopDown) || (Orient == kBottomUp))
- {
- familySize.h = Max(childSize.h, nodeSize.h);
- familySize.v = nodeSize.v;
- if (childSize.v > 0)
- familySize.v += childSize.v + GetBranchLength();
- }
- else
- {
- familySize.v = Max(childSize.v, nodeSize.v);
- familySize.h = nodeSize.h;
- if (childSize.h > 0)
- familySize.h += childSize.h + GetBranchLength();
- }
-
- }
-
- /*-----------------------------------------------------------------*/
- /*---------------------- START NORMAL TREE ------------------------*/
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTreeNode::DoCalcFamilyBounds(Point TopLeftCorner)
- /* This routine uses the orientation and justification of the */
- /* tree to determine where every node should be in relation to */
- /* all the others. */
- /* NOTE: this routine assumes that the child/node/familySize */
- /* variables are set correctly, so if any node has changed size, */
- /* you should call CalcFamilySize before this routine */
- {
- Rect OldNodeRect = this->nodeRect,
- OldGChildRect = this->gChildRect;
-
- Rect newNodeRect = {0, 0, 0, 0},
- newChildRect = {0, 0, 0, 0},
- newFamilyRect = {0, 0, 0, 0},
- newGChildRect = {0, 0, 0, 0};
-
- Boolean eraseKidJoins = FALSE;
- orientStyle Orient = GetOrientation();
- short betweenNodeMargin = GetNodeMargin();
- justStyle Just = GetJustification();
- short Branch = GetBranchLength();
- Point TL = TopLeftCorner,
- L, R, T, B;
- CPPVisualTreeNode *theChild = NULL;
- long i = 0;
- Rect emptyRect = {0,0,0,0};
- short Sign = 1, Temp;
-
- if (this->numItems)
- { // this node is non terminal; its family's size depends on
- // the size of its children
- switch (Orient) {
-
- case kRight2Left :
- Sign = -1;
- case kLeft2Right :
- // The trick here is to step through each child, assimilating its
- // boundsrect into the family boundsrect.
- // Each time you come out of a calculate call, move TL down to the
- // most recently calculated bottommost position; this will become the
- // top left corner of the next child's boundsrect
- TL.h += (this->nodeSize.h + Branch) * Sign;
-
- // determine the node's rectangle
- if (Sign > 0)
- SetRect(&newNodeRect, TopLeftCorner.h, TopLeftCorner.v,
- TopLeftCorner.h + this->nodeSize.h,
- TopLeftCorner.v + this->nodeSize.v);
- else // TopLeft is actually TopRight
- SetRect (&newNodeRect, TopLeftCorner.h - this->nodeSize.h,
- TopLeftCorner.v, TopLeftCorner.h,
- TopLeftCorner.v + this->nodeSize.v);
-
- // if the children are not as tall as the parent, we have to pad
- // TL.v so that they will be justified correctly
- if (this->childSize.v < this->nodeSize.v)
- {
- switch (Just) {
- case kJustBottom :
- TL.v += (this->nodeSize.v - this->childSize.v);
- break;
- case kJustCenter :
- TL.v += ceil ((this->nodeSize.v - this->childSize.v) / 2.0);
- break;
- } // switch
- } // if
-
- // calculate bounds for the children, then assimilate them
- for (i=1;i<=this->numItems;i++)
- {
- theChild = (CPPVisualTreeNode *)NthChild(i);
- if (theChild)
- {
- theChild->DoCalcFamilyBounds(TL);
- TL.v += (theChild->familyRect.bottom - theChild->familyRect.top);
- if (i != this->numItems)
- TL.v += betweenNodeMargin;
- if (i != 1)
- {
- UnionRect(&newChildRect, &theChild->familyRect, &newChildRect);
- UnionRect(&newGChildRect, &theChild->nodeRect, &newGChildRect);
- }
- else
- {
- newChildRect = theChild->familyRect;
- newGChildRect = theChild->nodeRect;
- }
- }
- }
-
- // construct the family's rectangle
- if (EqualRect(&newChildRect, &emptyRect))
- newFamilyRect = newNodeRect;
- else
- UnionRect (&newChildRect, &newNodeRect, &newFamilyRect);
-
- // now use the justification to position the node's rectangle
- switch (Just) {
- case kJustBottom :
- OffsetRect(&newNodeRect, 0, (newFamilyRect.bottom -
- newNodeRect.bottom));
- break;
- case kJustCenter :
- if (this->numItems > 1)
- {
- ((CPPVisualTreeNode *)NthChild(1))->GetAnchorPoints (&L, &R, &T, &B);
- Temp = R.v;
- ((CPPVisualTreeNode *)NthChild(this->numItems))->GetAnchorPoints (&L, &R, &T, &B);
- OffsetRect (&newNodeRect, 0, (Temp + ((R.v - Temp) / 2)) -
- (newNodeRect.top + ((newNodeRect.bottom - newNodeRect.top) / 2)));
- }
- else
- OffsetRect(&newNodeRect, 0, (newFamilyRect.bottom -
- newNodeRect.bottom) / 2);
- break;
- } /*switch Distribution */
-
- break;
-
-
- case kBottomUp :
- Sign = -1;
- case kTopDown :
- // The trick here is to step through each child, assimilating its
- // boundsrect into the family boundsrect.
- // Each time you come out of a calculate call, move TL down to the
- // most recently calculated rightmost position; this will become the
- // top left corner of the next child's boundsrect
- TL.v += (this->nodeSize.v + Branch) * Sign;
-
- // determine the node's rectangle
- if (Sign > 0)
- SetRect(&newNodeRect, TopLeftCorner.h, TopLeftCorner.v,
- TopLeftCorner.h + this->nodeSize.h,
- TopLeftCorner.v + this->nodeSize.v);
- else // TopLeft is actually BottomLeft
- SetRect(&newNodeRect, TopLeftCorner.h,
- TopLeftCorner.v - this->nodeSize.v,
- TopLeftCorner.h + this->nodeSize.h,
- TopLeftCorner.v);
-
- // if the children are not as wide as the parent, we have to pad
- // TL.h so that they will be justified correctly
- if (this->childSize.h < this->nodeSize.h)
- {
- switch (Just) {
- case kJustRight :
- TL.h += (this->nodeSize.h - this->childSize.h);
- break;
- case kJustCenter :
- TL.h += ceil((this->nodeSize.h - this->childSize.h) / 2.0);
- break;
- } // switch
- } // if
-
- // calculate bounds for the children, then assimilate them
- for (i=1;i<=this->numItems;i++)
- {
- theChild = (CPPVisualTreeNode *)NthChild(i);
- if (theChild)
- {
- theChild->DoCalcFamilyBounds(TL);
- TL.h += (theChild->familyRect.right - theChild->familyRect.left);
- if (i != this->numItems)
- TL.h += betweenNodeMargin;
- if (i != 1)
- {
- UnionRect(&newChildRect, &theChild->familyRect, &newChildRect);
- UnionRect(&newGChildRect, &theChild->nodeRect, &newGChildRect);
- }
- else
- {
- newChildRect = theChild->familyRect;
- newGChildRect = theChild->nodeRect;
- }
- }
- }
-
- // construct the family's rectangle
- if (EqualRect(&newChildRect, &emptyRect))
- newFamilyRect = newNodeRect;
- else
- UnionRect (&newChildRect, &newNodeRect, &newFamilyRect);
-
- // now use the justification to position the family's rectangle
- switch (Just) {
- case kJustRight :
- OffsetRect(&newNodeRect, (newFamilyRect.right -
- newNodeRect.right), 0);
- break;
- case kJustCenter :
- if (this->numItems > 1)
- {
- ((CPPVisualTreeNode *)NthChild(1))->GetAnchorPoints (&L, &R, &T, &B);
- Temp = T.h;
- ((CPPVisualTreeNode *)NthChild(this->numItems))->GetAnchorPoints (&L, &R, &T, &B);
- OffsetRect (&newNodeRect, (Temp + ((T.h - Temp) / 2)) -
- (newNodeRect.left + ((newNodeRect.right - newNodeRect.left) / 2)), 0);
- }
- else
- {
- ((CPPVisualTreeNode *)NthChild(1))->GetAnchorPoints (&L, &R, &T, &B);
- OffsetRect(&newNodeRect, T.h - (newNodeRect.left + ((newNodeRect.right - newNodeRect.left) / 2)), 0);
- }
- break;
- } /*switch Distribution */
-
- break;
-
- }
- }
- else
- { // terminal node; family size is based on nodeSize alone
- switch (Orient) {
- case kTopDown : // TopLeft is TopLeft
- case kLeft2Right :
- SetRect (&newNodeRect, TopLeftCorner.h, TopLeftCorner.v,
- TopLeftCorner.h + this->nodeSize.h,
- TopLeftCorner.v + this->nodeSize.v);
- break;
- case kBottomUp: // TopLeft is BottomLeft
- SetRect (&newNodeRect, TopLeftCorner.h,
- TopLeftCorner.v - this->nodeSize.v,
- TopLeftCorner.h + this->nodeSize.h,
- TopLeftCorner.v);
- break;
- case kRight2Left : // TopLeft is TopRight
- SetRect (&newNodeRect, TopLeftCorner.h - this->nodeSize.h,
- TopLeftCorner.v,
- TopLeftCorner.h,
- TopLeftCorner.v + this->nodeSize.v);
- break;
- }
- newFamilyRect = newNodeRect;
- }
-
- #include <TreeNodeConds.cp>
-
- this->nodeRect = newNodeRect;
- this->childRect = newChildRect;
- this->familyRect = newFamilyRect;
- this->gChildRect = newGChildRect;
-
- this->notYetPlaced = FALSE;
- }
-
- /*-----------------------------------------------------------------*/
-
- long CPPVisualTreeNode::NumSelectedNodes (CPPVisualTreeNode *theNode)
- /* return the number of nodes in the family which are selected */
- /* NOTE: The family head is included in the count */
- {
- long count = 0;
-
- if (theNode)
- ApplyToFamily (theNode, CountSelected, (long)(&count));
-
- return count;
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTreeNode::SetSelect (short selectType,
- Boolean selectFamily,
- Boolean doRedraw)
- /* Set the selection state of the node according to the passed */
- /* in value. Redraw the node if asked, and pass the selection */
- /* state down to the node's children if asked */
- {
- short oldValue = this->isSelected;
-
- switch (selectType) {
-
- case kSetSelect :
- this->isSelected = TRUE;
- if (!oldValue && doRedraw)
- this->DrawNode(FALSE, TRUE); // redraw if requested
- break;
-
- case kClearSelect :
- this->isSelected = FALSE;
- if (oldValue && doRedraw)
- this->DrawNode(FALSE, TRUE); // redraw if requested
- break;
-
- case kToggleSelect :
- this->isSelected = !oldValue;
- if (doRedraw)
- this->DrawNode(FALSE, TRUE); // redraw if requested
- break;
- }
-
- // if asked, pass it on to the node's children
- if (selectFamily)
- for (long i = 1; i <= this->numItems; i++)
- ((CPPVisualTreeNode *)NthChild(i))->
- SetSelect(selectType, selectFamily, doRedraw);
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTreeNode::GetAnchorPoints (Point *Left, Point *Right,
- Point *Top, Point *Bottom)
- /* Return the points on the left, right, top, and bottom where the */
- /* joins should start/end */
- {
- short halfWidth = (nodeRect.right - nodeRect.left) / 2;
- short halfHeight = (nodeRect.bottom - nodeRect.top) / 2;
-
- SetPt (Left, nodeRect.left-1, nodeRect.top + halfHeight);
- SetPt (Right, nodeRect.right, nodeRect.top + halfHeight);
- SetPt (Top, nodeRect.left + halfWidth, nodeRect.top-1);
- SetPt (Bottom, nodeRect.left + halfWidth, nodeRect.bottom);
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTreeNode::ReceiveMessage (CPPGossipMonger *toldBy,
- short reason, void* info)
- {
- Point oldTopLeft = {this->familyRect.top, this->familyRect.left};
- Rect oldFamilyRect = this->familyRect;
- Point OldFamilySize = this->familySize,
- OldChildSize = this->childSize,
- OldNodeSize = this->nodeSize;
- Boolean childChanged, familyChanged;
- RgnHandle Rgn1, Rgn2;
- static short timesCalled = 0; // tracks recursion
-
- switch (reason) {
- case kEraseFamily :
- EraseNode ((Boolean)info);
- break;
-
- case kDrawFamily :
- DrawNode ((Boolean)info, TRUE);
- break;
-
- case kResizeFamily :
- ResizeFamily (TRUE);
- if (this->Root)
- ((CPPVisualTree *)this->Root)->AdjustTree();
- break;
-
- case kMoveFamily :
- MoveFamily ((Point *)info);
- if (this->Root)
- ((CPPVisualTree *)this->Root)->AdjustTree();
- break;
-
- case kPrepareRemove :
- case kPrepareDelete :
- ((CPPVisualTreeNode *)info)->EraseNode(TRUE);
- ApplyToFamily((CPPVisualTreeNode *)info, SetNotYetPlaced, TRUE);
- break;
-
- case kChildRemoved :
- case kChildDeleted :
- case kNodeAdded : // the parent of the added node receives this message first
- case kNodeChangedData :
- timesCalled++;
-
- if (timesCalled == 1)
- if (this->Root)
- ((CPPVisualTree *)this->Root)->Prepare((CPPObject *)1313L);
-
- this->needsResize = TRUE;
- this->needsMove = TRUE;
- CalcFamilySize(); // figure out how big everyone is
- CalcFamilyBounds (oldTopLeft); // figure out where everybody goes
-
- if (info)
- this->needsDraw = TRUE;
-
- if (this->Parent && !EqualRect(&oldFamilyRect, &this->familyRect))
- TellParent (reason, NULL);
-
- if (this->needsDraw)
- {
- this->DrawNode(TRUE, FALSE);
- if (this->Root)
- ((CPPVisualTree *)this->Root)->DrawAllJoins(TRUE);
- if ((OldFamilySize.h > this->familySize.h) || (OldFamilySize.v > this->familySize.v))
- {
- Rgn1 = NewRgn();
- Rgn2 = NewRgn();
- RectRgn(Rgn1, &oldFamilyRect);
- RectRgn(Rgn2, &this->familyRect);
- XorRgn (Rgn1, Rgn2, Rgn1);
- EraseRgn (Rgn1);
- DisposeRgn(Rgn1);
- DisposeRgn(Rgn2);
- }
- if (this->Root)
- ((CPPVisualTree *)this->Root)->AdjustTree();
- }
-
- timesCalled--;
- if (timesCalled == 0)
- if (this->Root)
- ((CPPVisualTree *)this->Root)->Restore((CPPObject *)1313L);
- break;
-
- default:
- CPPTreeNode::ReceiveMessage (toldBy, reason, info);
- break;
- }
-
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTreeNode::GetFamilyBounds (Rect *bounds)
- /* return the size of the node & its children */
- {
- *bounds = this->familyRect;
- }
-
- /*-----------------------------------------------------------------*/
-
- orientStyle CPPVisualTreeNode::GetOrientation (void)
- /* return the orientation used by the tree which this node belongs */
- /* to or topDown as a default */
- {
- return (this->Root) ?
- ((CPPVisualTree *)Root)->GetOrientation() : kTopDown;
- }
-
- /*-----------------------------------------------------------------*/
-
- short CPPVisualTreeNode::GetNodeMargin (void)
- /* return the orientation used by the tree which this node belongs */
- /* to or topDown as a default */
- {
- return (this->Root) ?
- ((CPPVisualTree *)Root)->GetNodeMargin() : 2;
- }
-
- /*-----------------------------------------------------------------*/
-
- justStyle CPPVisualTreeNode::GetJustification (void)
- /* return the justification used by the tree which this node belongs */
- /* to or kJustCenter as a default */
- {
- return (this->Root) ?
- ((CPPVisualTree *)Root)->GetJustification() : kJustCenter;
- }
-
- /*-----------------------------------------------------------------*/
-
- joinTypes CPPVisualTreeNode::GetJoinType (void)
- /* return the join type used by the tree which this node belongs */
- /* to or kRightAngle as a default */
- {
- return (this->Root) ?
- ((CPPVisualTree *)Root)->GetJoinType() : kRightAngle;
- }
-
- /*-----------------------------------------------------------------*/
-
- short CPPVisualTreeNode::GetBranchLength (void)
- /* return the branch length used by the tree which this node belongs */
- /* to or 25 as a default */
- {
- return (this->Root) ?
- ((CPPVisualTree *)Root)->GetBranchLength() : 25;
- }
-
- /*-----------------------------------------------------------------*/
-
- CPPVisualTreeNode *CPPVisualTreeNode::PointInNode (Point clickPt)
- /* If the point is in this node or any of its children, return */
- /* the node which was clicked in, otherwise, return FALSE */
- {
- CPPVisualTreeNode *childNode, *returnNode = NULL;
-
- if (PtInRect (clickPt, &nodeRect))
- return this;
- else
- if (PtInRect (clickPt, &childRect))
- {
- for (long i = 1; i <= this->numItems; i++)
- {
- if ((childNode = (CPPVisualTreeNode *)NthChild (i)) != NULL)
- if ((returnNode = childNode->PointInNode(clickPt)) != NULL)
- break;
- }
- return returnNode;
- }
- else
- return NULL;
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTreeNode::DoOnFamilyInRect (Rect *theRect,
- Boolean fullyInside,
- ApplyProc theProc, long param)
- /* If the node is either fully or partially inside the passed rect */
- /* call theProc to perform some operation on it */
- {
- CPPVisualTreeNode *childNode;
- Rect tempRect;
-
- // check to see if the rectangle intersects our own node
- if (SectRect (theRect, &this->nodeRect, &tempRect))
- {
- if (!fullyInside || (fullyInside && EqualRect (&tempRect, &this->nodeRect)))
- if (theProc)
- (*theProc)(this, param);
- }
-
- // if it intersects our children, apply SelectInRect to each child
- if (SectRect (theRect, &this->childRect, &tempRect))
- for (long i = 1; i <= this->numItems; i++)
- {
- if ((childNode = (CPPVisualTreeNode *)NthChild (i)) != NULL)
- childNode->DoOnFamilyInRect (theRect, fullyInside, theProc, param);
- }
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTreeNode::DoDoubleClick (short modifiers)
- /* Special action to perform when a node is double-clicked */
- /* SUBCLASS SHOULD OVERRIDE */
- {
-
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTreeNode::DoSingleClick (short modifiers)
- /* Special action to perform when a node is clicked */
- /* SUBCLASS SHOULD OVERRIDE */
- {
-
- }
-
-